package de.joergviola.mobj.client.database;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.code.gwt.database.client.GenericRow;
import com.google.code.gwt.database.client.SQLTransaction;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.client.rpc.AsyncCallback;

import de.joergviola.mobj.shared.Entity;
import de.joergviola.mobj.shared.EntityReader;
import de.joergviola.mobj.shared.ObjectNotFoundException;
import de.joergviola.mobj.shared.Persistable;
import de.joergviola.mobj.shared.Schema;

public class DBEntityReader implements EntityReader {

	private final GenericRow row;
	private final Barrier<?> barrier;
	private Schema schema;
	private SQLTransaction tx;

	public DBEntityReader(Schema schema, SQLTransaction tx, Barrier<?> barrier,
			GenericRow row) {
		this.schema = schema;
		this.tx = tx;
		this.barrier = barrier;
		this.row = row;
	}

	@Override
	public String readString(String name) {
		return row.getString(name);
	}

	@Override
	public Long readLong(String name) {
		return new Long(row.getInt(name));
	}

	@Override
	public Date readDate(String name) {
		String s = row.getString(name);
		if (s == null)
			return null;
		long ms = Long.parseLong(s);
		return new Date(ms);
	}

	@Override
	public Double readDouble(String name) {
		return row.getDouble(name);
	}

	private JSONArray getJSONArray(String name) {
		String data = row.getString(name);
		if (data == null)
			return null;
		JSONValue value = JSONParser.parseStrict(data);
		JSONArray array = value.isArray();
		return array;
	}

	@Override
	public List<Long> readListLong(String name) {
		JSONArray array = getJSONArray(name);
		if (array == null)
			return null;
		ArrayList<Long> result = new ArrayList<Long>();
		for (int i = 0; i < array.size(); i++) {
			JSONValue value = array.get(i);
			JSONNumber n = value.isNumber();
			Long l = new Long((long) n.doubleValue());
			result.add(l);
		}
		return result;
	}

	@Override
	public String[] readStringArray(String name) {
		JSONArray array = getJSONArray(name);
		if (array == null)
			return null;
		String[] result = new String[array.size()];
		for (int i = 0; i < array.size(); i++) {
			JSONValue value = array.get(i);
			JSONString s = value.isString();
			result[i] = s.stringValue();
		}
		return result;
	}

	@Override
	public List<String> readListString(String name) {
		JSONArray array = getJSONArray(name);
		if (array == null)
			return null;
		ArrayList<String> result = new ArrayList<String>();
		for (int i = 0; i < array.size(); i++) {
			JSONValue value = array.get(i);
			JSONString s = value.isString();
			result.add(s.stringValue());
		}
		return result;
	}

	@Override
	public <T extends Persistable> void readPersistable(String name,
			Class<T> clazz, final AsyncCallback<T> setter)
			throws ObjectNotFoundException {
		int id = row.getInt(name);
		Entity<T> entity = schema.getEntity(clazz);
		// null check?
		Get<T> get = new Get<T>(schema, entity);
		barrier.enter();
		get.execute(tx, new Long(id), new AsyncCallback<T>() {

			@Override
			public void onFailure(Throwable caught) {
				barrier.onFailure(caught);
			}

			@Override
			public void onSuccess(T result) {
				setter.onSuccess(result);
				barrier.onSuccess();
			}
		});
	}
}
